package com.ruoyi.gateway.authorization;

import cn.hutool.core.convert.Convert;
import com.ruoyi.common.core.constant.TokenConstants;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.core.utils.reflect.ReflectUtils;
import com.ruoyi.gateway.config.properties.IgnoreWhiteProperties;
import com.sun.media.jfxmedia.logging.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpMethod;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.ReactiveAuthorizationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.server.authorization.AuthorizationContext;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;
import java.net.URI;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 鉴权管理器，用于判断是否有资源的访问权限
 * Created by xieqq on 2020/6/19.
 */
@Component
public class AuthorizationManager implements ReactiveAuthorizationManager<AuthorizationContext> {
    private static org.slf4j.Logger logger = LoggerFactory.getLogger(AuthorizationManager.class);

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private IgnoreWhiteProperties ignoreWhite;

    @Override
    public Mono<AuthorizationDecision> check(Mono<Authentication> mono, AuthorizationContext authorizationContext) {
        ServerHttpRequest request = authorizationContext.getExchange().getRequest();
        URI uri = request.getURI();
        logger.error("=====authorization manager uri {}", uri.getPath());
        PathMatcher pathMatcher = new AntPathMatcher();
        if(pathMatcher.match("/system/user/getInfo", uri.getPath()) ||
                pathMatcher.match("/system/menu/getRouters", uri.getPath()) ) {
            // 获取信息直接放行，AuthFilter才可以设置header 后获取角色

            return Mono.just(new AuthorizationDecision(true));
        }

        //白名单路径直接放行
        List<String> ignoreUrls = ignoreWhite.getWhites();
        for (String ignoreUrl : ignoreUrls) {
            if (pathMatcher.match(ignoreUrl, uri.getPath())) {
                return Mono.just(new AuthorizationDecision(true));
            }
        }
        //对应跨域的预检请求直接放行
        if(request.getMethod()==HttpMethod.OPTIONS){
            return Mono.just(new AuthorizationDecision(true));
        }
//        //不同用户体系登录不允许互相访问
//        try {
//            String token = request.getHeaders().getFirst(TokenConstants.AUTHENTICATION);
//            if(StringUtils.isEmpty(token)){
//                return Mono.just(new AuthorizationDecision(false));
//            }// 根据token解析出用户信息
//            String realToken = token.replace(TokenConstants.PREFIX, "");
//            JWSObject jwsObject = JWSObject.parse(realToken);
//            String userStr = jwsObject.getPayload().toString();
//            UserDto userDto = JSONUtil.toBean(userStr, UserDto.class);
//            if (AuthConstant.ADMIN_CLIENT_ID.equals(userDto.getClientId()) && !pathMatcher.match(AuthConstant.ADMIN_URL_PATTERN, uri.getPath())) {
//                return Mono.just(new AuthorizationDecision(false));
//            }
//            if (AuthConstant.PORTAL_CLIENT_ID.equals(userDto.getClientId()) && pathMatcher.match(AuthConstant.ADMIN_URL_PATTERN, uri.getPath())) {
//                return Mono.just(new AuthorizationDecision(false));
//            }
//        } catch (ParseException e) {
//            e.printStackTrace();
//            return Mono.just(new AuthorizationDecision(false));
//        }
//        //非管理端路径直接放行
//        if (!pathMatcher.match(AuthConstant.ADMIN_URL_PATTERN, uri.getPath())) {
//            return Mono.just(new AuthorizationDecision(true));
//        }
        //管理端路径需校验权限 // 权限存在redis中
        Map<Object, Object> resourceRolesMap = redisTemplate.opsForHash().entries("token");//AuthConstant.RESOURCE_ROLES_MAP_KEY);
        Iterator<Object> iterator = resourceRolesMap.keySet().iterator();
        List<String> authorities = new ArrayList<>();
        while (iterator.hasNext()) {
            String pattern = (String) iterator.next();
            if (pathMatcher.match(pattern, uri.getPath())) {
                authorities.addAll(Convert.toList(String.class, resourceRolesMap.get(pattern)));
            }
        }
        authorities = authorities.stream().map(i -> i = TokenConstants.PREFIX + i).collect(Collectors.toList());
        //认证通过且角色匹配的用户可访问当前路径
//        return mono
//                .filter(Authentication::isAuthenticated)
//                .flatMapIterable(Authentication::getAuthorities)
//                .map(GrantedAuthority::getAuthority)
//                .any(authorities::contains)
//                .map(AuthorizationDecision::new)
//                .defaultIfEmpty(new AuthorizationDecision(false));
        return Mono.just(new AuthorizationDecision(true)); // 测试环境直接全部放行
    }

}
